package com.alfy.sbdemo.websocketdemo.demo2;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 本类是继承 TextWebSocketHandler 类的 WebSocket 处理类。
 * 最终实现于 WebSocketHandler 接口，用于创建 WebSocket 消息和生命周期事件的处理程序。
 */
public class MyWebSocketHandler extends TextWebSocketHandler {

    /**
     * 存储 WebSocket 客户端连接
     */
    private static final Map<String, WebSocketSession> connections = new HashMap<>();

    /**
     * 相当于 open 事件, 是在建立连接后触发
     *
     * @param session session
     * @throws Exception exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("open 事件 --- 成功建立 WebSocket 连接, sessionId: " + session.getId() + ", 当前客户端连接数: " + (connections.size() + 1));
        System.out.println("open 事件 --- 当前处理程序为: " + this + ", RequestAttributes: " + RequestContextHolder.getRequestAttributes());
        // 建立连接后将连接以键值对方式存储, 便于后期向客户端发送消息
        // 以客户端连接的唯一标识为 key, 可以通过客户端发送唯一标识
        connections.put(session.getId(), session);
        // 获取地址参数
        System.out.println("open 事件 --- 传入参数: " + session.getAttributes());
    }

    /**
     * 相当于 message 事件, 用于接收客户端消息
     *
     * @param session session
     * @param message message
     * @throws Exception exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        System.out.println("message 事件 --- 收到消息（" + session.getId() + "）: " + message.getPayload() + ", RequestAttributes: " + RequestContextHolder.getRequestAttributes());
        // 收到客户端请求消息后进行相应业务处理，返回结果
        this.sendMessage(session.getId(), message.getPayload());
        System.out.println("close 事件 --- 接收到参数: " + session.getAttributes());
    }

    /**
     * 向连接的客户端发送消息的方法
     *
     * @param clientId 客户端标识
     * @param message  消息体
     */
    public void sendMessage(String clientId, String message) {
        for (String client : connections.keySet()) {
            try {
                WebSocketSession session = connections.get(client);
                TextMessage textMessage = null;
                if (client.equals(clientId)) {
                    textMessage = new TextMessage("发送成功: " + message);
                }else {
                    textMessage = new TextMessage("收到消息: " + message);
                }
                // 判断连接是否正常
                if (session.isOpen()) {
                    session.sendMessage(textMessage);
                }
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }
        }
    }

    /**
     * 相当于 close 事件, 关闭连接时触发
     *
     * @param session session
     * @param status  status
     * @throws Exception exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        System.out.println("close 事件 --- WebSocket 连接关闭后回调, " + status.toString() + ", RequestAttributes: " + RequestContextHolder.getRequestAttributes());
        connections.remove(session.getId()); // 移除连接
        System.out.println("close 事件 --- 接收到参数: " + session.getAttributes());
    }

    /**
     * 相当于 error 事件, 传输异常处理
     *
     * @param session   session
     * @param exception exception
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.out.println("error 事件 --- 连接发生错误被回调 ~~~~");
        super.handleTransportError(session, exception);
    }

    /**
     * supports partial messages
     *
     * @return boolean
     */
    @Override
    public boolean supportsPartialMessages() {
        return super.supportsPartialMessages();
    }

}

// close 事件 --- WebSocket 连接关闭后回调, CloseStatus[code=1000, reason=null], RequestAttributes: null
// close 事件 --- 接收到参数: {name=ws, test=test}
// 拦截器前置触发, wsHandler: ExceptionWebSocketHandlerDecorator [delegate=LoggingWebSocketHandlerDecorator [delegate=com.alfy.sbdemo.websocketdemo.demo2.MyWebSocketHandler@3c35c345]], attributes: {}, RequestAttributes: org.apache.catalina.connector.RequestFacade@72397d1d
// 拦截器前置触发, 获取参数 name: ws
// 拦截器前置触发, 基础校验通过（ws）, 允许建立链接
// 拦截器后置触发, , ExceptionWebSocketHandlerDecorator [delegate=LoggingWebSocketHandlerDecorator [delegate=com.alfy.sbdemo.websocketdemo.demo2.MyWebSocketHandler@3c35c345]], ex: null, RequestAttributes: org.apache.catalina.connector.RequestFacade@72397d1d
// open 事件 --- 成功建立 WebSocket 连接, sessionId: d810a073-1628-07f4-e4c4-ca61fb91c9ad, 当前客户端连接数: 1
// open 事件 --- 当前处理程序为: com.alfy.sbdemo.websocketdemo.demo2.MyWebSocketHandler@3c35c345, RequestAttributes: null
// open 事件 --- 传入参数: {name=ws, test=test}
// message 事件 --- 收到消息（d810a073-1628-07f4-e4c4-ca61fb91c9ad）: 客户端内容, RequestAttributes: null
// close 事件 --- 接收到参数: {name=ws, test=test}
